﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RStarTree;
using MPlusTree;
using System.Collections;
using TSTreeThesis.Utilities;
using TSTree;
using TSTreeSAX;

namespace TSTreeThesis.DataMgr
{
    public class IndexMgr
    {
        private FileData data;
        private MPTree<MPTreeKey> mptreeIndex;
        private RTree rtreeIndex;
        private TRTree tstreeIndex;
        private STRTree tstreeIndexSax;

        private double mean = 0;
        private double std = 1;

        public void SetMeanValue(double mean)
        {
            this.mean = mean;
        }

        public double GetMeanValue()
        {
            return mean;
        }

        public void SetStdValue(double std)
        {
            this.std = std;
        }

        public double GetStdValue()
        {
            return std;
        }


        public void SetData(FileData data)
        {
            this.data = data;
        }

        public FileData GetData()
        {
            return data;
        }

        public void SetMPTree(MPTree<MPTreeKey> mptreeIndex)
        {
            this.mptreeIndex = mptreeIndex;
        }

        public MPTree<MPTreeKey> GetMPTree()
        {
            return mptreeIndex;
        }


        public void SetRStarTree(RTree rtreeIndex)
        {
            this.rtreeIndex = rtreeIndex;
        }

        public RTree GetRStarTree()
        {
            return rtreeIndex;
        }

        public void SetTSTree(TRTree tstreeIndex)
        {
            this.tstreeIndex = tstreeIndex;
        }

        public TRTree GetTSTree()
        {
            return tstreeIndex;
        }
        public void SetTSTreeSax(STRTree tstreeIndex)
        {
            this.tstreeIndexSax = tstreeIndex;
        }

        public STRTree GetTSTreeSAX()
        {
            return tstreeIndexSax;
        }

        public ArrayList SearchDataIndex(MPTreeKey query, double threshold)
        {
            if (query == null || query.GetNumDimension() != Utility.SLIDING_WINDOW_SIZE * Utility.COMPRESSION_RATE)
                throw new Exception("Null or invalid dimension query");
            if (mptreeIndex == null)
                throw new NullReferenceException("Null M+ Tree index");
            ArrayList resIndex = new ArrayList();
            ArrayList tempIndex = new ArrayList();

            float[] transform = (new PAATransform()).Transform(Utility.COMPRESSION_RATE, query.GetData());
            float[] encodedQueryData = new float[query.GetNumDimension() / Utility.COMPRESSION_RATE];

            Array.Copy(transform, 0, encodedQueryData, 0, query.GetNumDimension() / Utility.COMPRESSION_RATE);

            MPTreeKey k = new MPTreeKey();
            k.SetData(transform);

            //GiSTlist results = mtreeIndex.rangeSearch(new TSSegmentKey(encodedQuery), threshold);

            MPQueryObj qObj = new MPQueryObj();
            qObj.SetKey(k);
            LinkedList<MPKey> results = new LinkedList<MPKey>();
            mptreeIndex.RangeSearch(qObj, (float)threshold, results);

            foreach (MPKey result in results)
            {
                int index = ((MPTreeKey)result).GetIndex();

                int dim = Utility.COMPRESSION_RATE * Utility.SLIDING_WINDOW_SIZE;
                float[] realSubData = new float[dim];
                for (int j = 0; j < dim; j++)
                {
                    realSubData[j] = (float)data.nomalizedData[index * Utility.COMPRESSION_RATE + j];
                }

                //Revising the results
                if (Utility.EuclideDistance(realSubData, query.GetData()) < threshold)
                {
                    tempIndex.Add(index);
                }

            }

            //Skip trivial results
            tempIndex.Sort();
            //if (tempIndex.Count > 0) resIndex.Add((int)tempIndex[0]);
            for (int i = 0; i < tempIndex.Count; i++)
            {
                bool skipping;
                resIndex.Add(tempIndex[i]);

                //if (i < tempIndex.Count - 1)
                //{
                //    skipping = true;
                //    while (skipping && (i < tempIndex.Count - 1))
                //    {
                //        if ((int)tempIndex[i] == ((int)tempIndex[i + 1] - 1)) i++;
                //        else skipping = false;
                //    }
                //}


                //if (i < tempIndex.Count - 1)
                //{
                //    int j = 0;
                //    skipping = true;
                //    while (skipping && (i < tempIndex.Count - 1) && j < Utility.SLIDING_WINDOW_SIZE_ORIGINAL)
                //    {
                //        if ((int)tempIndex[i] == ((int)tempIndex[i + 1] - 1)) i++;
                //        else skipping = false;

                //        ++j;
                //    }
                //}


                if (i < tempIndex.Count - 1)
                {
                    int j = i;
                    skipping = true;
                    while (skipping && (i < tempIndex.Count - 1))
                    {
                        if ((int)tempIndex[j] > ((int)tempIndex[i + 1] - Utility.SLIDING_WINDOW_SIZE)) i++;
                        else skipping = false;
                    }
                }


                //  if(((int)tempIndex[i]-Utility.SLIDING_WINDOW_SIZE)>((int)tempIndex[i-1]))

            }
            return resIndex;
            //return tempIndex;
        }
        //private 


        public ArrayList SearchDataIndex(PPoint query, float threshold)
        {
            if (query == null || query.dimension != Utility.SLIDING_WINDOW_SIZE * Utility.COMPRESSION_RATE)
                throw new Exception("Null or invalid dimension query");
            if (rtreeIndex == null)
                throw new NullReferenceException("Null R Start Tree index");
            ArrayList resIndex = new ArrayList();
            ArrayList tempIndex = new ArrayList();
            SortedLinList results = new SortedLinList();
            PPoint encodedQuery = new PPoint(Utility.SLIDING_WINDOW_SIZE);

            encodedQuery.data = (new PAATransform()).Transform(Utility.COMPRESSION_RATE, query.data);

            DateTime dt = DateTime.Now;
            rtreeIndex.rangeQuery(encodedQuery, threshold, results);
            Utility.SEARCH_TIME_RTREE = (int)DateTime.Now.Subtract(dt).TotalMilliseconds;

            //  int[] queryIndex = new int[results.getNoOfElements()];
            Utility.SEARCH_CANDIDATE_RTREE = results.getNoOfElements();

            for (int i = 0; i < results.getNoOfElements(); i++)
            {
                int index = ((RStarTree.Data)results.get(i)).id;

                int dim = Utility.COMPRESSION_RATE * Utility.SLIDING_WINDOW_SIZE;
                double[] realSubData = new double[dim];
                for (int j = 0; j < dim; j++)
                {
                    realSubData[j] = data.nomalizedData[index * Utility.COMPRESSION_RATE + j];
                }

                //Revising the results
                //if (Utility.EuclideDistance(realSubData, query.data) < threshold)
                //{
                //    tempIndex.Add(index);
                //}

                if (Utility.DTWdistance(query.data, realSubData) < threshold)
                {
                    tempIndex.Add(index);
                }

            }

            //Skip trivial results
            tempIndex.Sort();
            //if (tempIndex.Count > 0) resIndex.Add((int)tempIndex[0]);
            for (int i = 0; i < tempIndex.Count; i++)
            {
                bool skipping;
                resIndex.Add(tempIndex[i]);

                //if (i < tempIndex.Count - 1)
                //{
                //    skipping = true;
                //    while (skipping && (i < tempIndex.Count - 1))
                //    {
                //        if ((int)tempIndex[i] == ((int)tempIndex[i + 1] - 1)) i++;
                //        else skipping = false;
                //    }
                //}

                //if (i < tempIndex.Count - 1)
                //{
                //    int j = 0;
                //    skipping = true;
                //    while (skipping && (i < tempIndex.Count - 1) && j < Utility.SLIDING_WINDOW_SIZE_ORIGINAL)
                //    {
                //        if ((int)tempIndex[i] == ((int)tempIndex[i + 1] - 1)) i++;
                //        else skipping = false;

                //        ++j;
                //    }
                //}

                if (i < tempIndex.Count - 1)
                {
                    int j = i;
                    skipping = true;
                    while (skipping && (i < tempIndex.Count - 1))
                    {
                        if ((int)tempIndex[j] > ((int)tempIndex[i + 1] - Utility.SLIDING_WINDOW_SIZE)) i++;
                        else skipping = false;
                    }
                }

                //  if(((int)tempIndex[i]-Utility.SLIDING_WINDOW_SIZE)>((int)tempIndex[i-1]))

            }
           // Utility.SEARCH_TIME_RTREE = (int)DateTime.Now.Subtract(dt).TotalMilliseconds;
            return resIndex;
            //return tempIndex;
        }

        public ArrayList SearchDataIndex(TSPoint query, float threshold)
        {
            if (query == null || query.dimension != Utility.SLIDING_WINDOW_SIZE * Utility.COMPRESSION_RATE)
                throw new Exception("Null or invalid dimension query");
            if (tstreeIndex == null)
                throw new NullReferenceException("Null TS Start Tree index");
            ArrayList resIndex = new ArrayList();
            ArrayList tempIndex = new ArrayList();
            TSTree.fuctions.SortedLinList results = new TSTree.fuctions.SortedLinList();
            TSPoint encodedQuery = new TSPoint(Utility.SLIDING_WINDOW_SIZE);

            encodedQuery.data = (new PAATransform()).Transform(Utility.COMPRESSION_RATE, query.data);

            tstreeIndex.rangeQuery(encodedQuery, threshold, results);

           
            for (int i = 0; i < results.getNoOfElements(); i++)
            {
                int index = ((TSTree.TSData)results.get(i)).id;

                int dim = Utility.COMPRESSION_RATE * Utility.SLIDING_WINDOW_SIZE;
                double[] realSubData = new double[dim];
                for (int j = 0; j < dim; j++)
                {
                    realSubData[j] = data.nomalizedData[index * Utility.COMPRESSION_RATE + j];
                }

                //Revising the results
                //if (Utility.EuclideDistance(realSubData, query.data) < threshold)
                //{
                //    tempIndex.Add(index);
                //}

                if (Utility.DTWdistance(query.data, realSubData) < threshold)
                {
                    tempIndex.Add(index);
                }

               // tempIndex.Add(index);

            }
          
            //Skip trivial results
            tempIndex.Sort();
           
            for (int i = 0; i < tempIndex.Count; i++)
            {
                bool skipping;
                resIndex.Add(tempIndex[i]);

                if (i < tempIndex.Count - 1)
                {
                    int j = i;
                    skipping = true;
                    while (skipping && (i < tempIndex.Count - 1))
                    {
                        if ((int)tempIndex[j] > ((int)tempIndex[i + 1] - Utility.SLIDING_WINDOW_SIZE)) i++;
                        else skipping = false;
                    }
                }


            }

            return resIndex;
           
        }

        public ArrayList SearchDataIndex(STSPoint query, float threshold, int length, int max, int min)
        {
            if (query == null || query.dimension != Utility.SLIDING_WINDOW_SIZE * Utility.COMPRESSION_RATE)
                throw new Exception("Null or invalid dimension query");
            if (tstreeIndexSax == null)
                throw new NullReferenceException("Null TS Start Tree index");
            ArrayList resIndex = new ArrayList();
            ArrayList tempIndex = new ArrayList();
            TSTreeSAX.fuctions.SortedLinList results = new TSTreeSAX.fuctions.SortedLinList();
            STSPoint encodedQuery = new STSPoint(Utility.SLIDING_WINDOW_SIZE);

            float[] tempdata = (new PAATransform()).Transform(Utility.COMPRESSION_RATE, query.fdata);

            double _max = tempdata.Max(); //Console.WriteLine("max : " + _max.ToString()); // Math.Round((max - this.mean) / this.std, 2);
            double _min = tempdata.Min(); //Console.WriteLine("min: "+ _min.ToString()); // Math.Round((min - this.mean) / this.std, 2);
           
            encodedQuery.data = (new SAXTransform()).SaxTranform(tempdata, _max, _min, length, Utility.SLIDING_WINDOW_SIZE);
            Array.Copy(tempdata, 0, encodedQuery.fdata, 0, Utility.SLIDING_WINDOW_SIZE);

            DateTime dt = DateTime.Now;
            tstreeIndexSax.rangeQuery(encodedQuery, threshold, results);
            Utility.SEARCH_TIME_TSTREE = (int)DateTime.Now.Subtract(dt).TotalMilliseconds;

            //  int[] queryIndex = new int[results.getNoOfElements()];
            Utility.SEARCH_CANDIDATE_TSTREE = results.getNoOfElements();

            for (int i = 0; i < results.getNoOfElements(); i++)
            {
                int index = ((TSTreeSAX.STSData)results.get(i)).id;

                int dim = Utility.COMPRESSION_RATE * Utility.SLIDING_WINDOW_SIZE;
                double[] realSubData = new double[dim];
                for (int j = 0; j < dim; j++)
                {
                    realSubData[j] = data.nomalizedData[index * Utility.COMPRESSION_RATE + j];
                }

 
                //Revising the results
                //Console.WriteLine("realSubData lengh  :" + realSubData.Length.ToString());
                //Console.WriteLine(" query.fdata lengh  :" + query.fdata.Length.ToString());

                if (Utility.DTWdistance(query.fdata, realSubData) < threshold)
                {
                    tempIndex.Add(index);
                }

     

            }

            //Skip trivial results
            tempIndex.Sort();
         
            for (int i = 0; i < tempIndex.Count; i++)
            {
                bool skipping;
                resIndex.Add(tempIndex[i]);

              
                if (i < tempIndex.Count - 1)
                {
                    int j = i;
                    skipping = true;
                    while (skipping && (i < tempIndex.Count - 1))
                    {
                        if ((int)tempIndex[j] > ((int)tempIndex[i + 1] - Utility.SLIDING_WINDOW_SIZE)) i++;
                        else skipping = false;
                    }
                }

                

            }
           
            return resIndex;
       
        }

        public float getRtreeEntriesPerNode(string info)
        {
            float f = 0;
            if (info == Utility.NOOF_ENTRIES_PER_INTERNAL_NODE)
            {
              f= rtreeIndex.avgEntriesPerInternalNode();
            }
            else if (info == Utility.NOOF_ENTRIES_PER_LEAF_NODE)
            {
              f= rtreeIndex.avgEntriesPerLeafNode();
            }
            return f;
        }
        public int getRtreeNodeByLevel(int level)
        {
            return rtreeIndex.noOfNodeLevel(level);
        }

        public float getTStreeEntriesPerNode(string info, bool isSax)
        {
            float f = 0;
            if (info == Utility.NOOF_ENTRIES_PER_INTERNAL_NODE)
            {
                f = (isSax == false) ? tstreeIndex.avgEntriesPerInternalNode() : tstreeIndexSax.avgEntriesPerInternalNode();
            }
            else if (info == Utility.NOOF_ENTRIES_PER_LEAF_NODE)
            {
                f = (isSax == false) ? tstreeIndex.avgEntriesPerLeafNode() : tstreeIndexSax.avgEntriesPerLeafNode();
            }
            return f;
        }
        public int getTStreeNodeByLevel(int level, bool isSax)
        {
            if (isSax)
            {
                return tstreeIndexSax.noOfNodeLevel(level);
            }
            else
            {
                return tstreeIndex.noOfNodeLevel(level);
            }
        }
    }
}
